#include "sound.h"

#ifndef SKYID_DISABLE_SOUND
namespace SkyID
{

SoundOGG::SoundOGG(Reader *reader)
{
	if (!isValid())
		return;
	mBuffer = new ALuint;
	alGenBuffers(1, mBuffer);
	setValid(check() && open(reader));
}

SoundOGG::~SoundOGG()
{
	stop();
	alSourcei(mID, AL_BUFFER, 0);
	alDeleteBuffers(1, mBuffer);
	check();
	delete mBuffer;
	mBuffer = NULL;
}

bool SoundOGG::open(Reader *reader)
{
	LOG_ASSERT(reader && reader->isValid());

	ov_callbacks callbacks;
	callbacks.read_func  = HelperOggRead;
	callbacks.seek_func  = NULL;
	callbacks.close_func = NULL;
	callbacks.tell_func  = NULL;

	OggVorbis_File oggStream;
	if (ov_open_callbacks(reader, &oggStream, NULL, 0, callbacks) < 0)
	{
		LOG_MSG("SoundOGG: wrong file signature\n");
		return false;
	}

	vorbis_info* info = ov_info(&oggStream, -1);
	vorbis_comment* comment = ov_comment(&oggStream, -1);

	mFormat = info->channels==1 ? AL_FORMAT_MONO16 : AL_FORMAT_STEREO16;
	mFrequency = info->rate;

	const uint32 bufferSize = 0x40000;
	char buffer[bufferSize], *data = NULL, *temp = NULL;
	uint32 size = 0, oldSize = 0;
	int bs, result;

	do
	{
		result = ov_read(&oggStream, buffer, bufferSize, 0, 2, 1, &bs);
		if (result < 0)
		{
			LOG_MSG("SoundOGG: error reading OGG file");
			delete[] data;
			return false;
		}
		oldSize = size;
		size += result;
		temp = new char[size];
		LOG_ASSERT(temp);
		memcpy(temp, data, oldSize);
		memcpy(temp+oldSize, buffer, result);
		delete[] data;
		data = temp;
	} while (result);

	alBufferData(*mBuffer, mFormat, data, size, mFrequency);
	alSourcei(mID, AL_BUFFER, *mBuffer);

	delete[] data;
	ov_clear(&oggStream);

	return true;
}

} // namespace SkyID
#endif // SKYID_DISABLE_SOUND
